package com.core.reach.cloudhub.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.core.reach.cloudhub.domain.CommonResult;
import com.core.reach.cloudhub.domain.Payment;
import com.core.reach.cloudhub.handler.CustomerBlockHandler;
import com.core.reach.cloudhub.handler.CustomerFallbackHandler;
import com.core.reach.cloudhub.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * @author ga.zhang
 * @version V1.0
 * @description: TODO
 * @date 2020/3/31 14:17
 **/
@Slf4j
@RestController
public class CircleBreakerController {

    @Resource
    private RestTemplate restTemplate;

    @Value("${service-url.nacos-user-service}")
    private String serviceUrl;

    @Resource
    private PaymentService paymentService;

    @GetMapping("/consumer/paymentSql/{id}")
//    @SentinelResource(value = "fallback")
    /**fallbackHandler负责业务运行时异常的处理*/
//    @SentinelResource(value = "fallback", fallback ="fallbackHandler")
    /**blockHandler负责控制台配置违规处理*/
//    @SentinelResource(value = "fallback", blockHandler ="blockHandler")
    /**blockHandler和fallbackHandler一起配置会优先blockHandler的处理*/
//    @SentinelResource(value = "fallback", blockHandler = "blockHandler", fallback = "fallbackHandler")
    /**exceptionsToIgnore忽略对异常IllegalArgumentException的处理，可配置多个异常*/
//    @SentinelResource(value = "fallback",
//            blockHandlerClass = CustomerBlockHandler.class, blockHandler = "blockHandler",
//            fallbackClass = CustomerFallbackHandler.class, fallback = "fallbackHandler",
//            exceptionsToIgnore = {IllegalArgumentException.class})
    /**
     * 使用blockHandlerClass或者fallbackClass时，需要保证处理方法为静态方法需要加上static关键字，并且
     * 方法的参数需要与原方法参数保持一致，然后blockHandler方法必须加上参数BlockException，fallbackHandler方法可以加上参数Throwable
     */
    @SentinelResource(value = "fallback",
            blockHandlerClass = CustomerBlockHandler.class, blockHandler = "blockHandler",
            fallbackClass = CustomerFallbackHandler.class, fallback = "fallbackHandler")
    public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(serviceUrl + "/paymentSql/" + id, CommonResult.class);
        if (id == 4L) {
            throw new IllegalArgumentException("非法参数异常----------------->id:" + id);
        } else if (ObjectUtils.isEmpty(result) || ObjectUtils.isEmpty(result.getData())) {
            throw new NullPointerException("空指针异常------------->没有该条件下的查询结果");
        }
        return result;
    }

//    public CommonResult<Payment> fallbackHandler(@PathVariable Long id, Throwable throwable) {
//        Payment payment = new Payment(id, null);
//        return new CommonResult<>(444, "兜底异常fallback handler，exception内容：" + throwable.getMessage(), payment);
//    }

//    public CommonResult<Payment> blockHandler(@PathVariable Long id, BlockException be) {
//        Payment payment = new Payment(id, null);
//        return new CommonResult<>(445, "blockHandler-sentinel限流，无此流水，exception内容：" + be.getMessage(), payment);
//    }



    //===========================openFeign=============================
    @GetMapping("/consumer/openFeign/paymentSql/{id}")
    public CommonResult<Payment> paymentSql(@PathVariable("id") Long id){
        return paymentService.paymentSql(id);
    }

}
